using System.Collections.Generic;
using LogSystem;
using UnityEngine;
using UnityEngine.Rendering;

namespace Yoozoo.Gameplay.City
{
    public class CityRealAiContainerManagerBase
    {
        public int ContainerId { get; }
        
        public virtual Transform RoomRootTran { get; protected set; }
        
        // key = RoleId value = dic dic.key = Uid value = npc
        public Dictionary<int, Dictionary<int, CityRealAiNpcController>> NpcTypeCtrlDic { get; }
        
        public Dictionary<int, CityRealAiGoodsController> GoodsCtrlDic { get; }
        
        public virtual bool IsLoadComplete { get; }

        protected CityRealAiConfigManager _cfgMgr;

        public CityRealAiContainerManagerBase(int containerId)
        {
            ContainerId = containerId;
            NpcTypeCtrlDic = new Dictionary<int, Dictionary<int,CityRealAiNpcController>>();
            GoodsCtrlDic = new Dictionary<int, CityRealAiGoodsController>();
            _cfgMgr = CityRealAiManager.GetInstance().ConfigMgr;
        }

        public virtual void AddNpcCtrl(CityRealAiNpcController npcCtrl)
        {
            npcCtrl.SetNpcRootParent();
            if (!NpcTypeCtrlDic.TryGetValue(npcCtrl.RoleId, out var ctrlDic))
            {
                ctrlDic = new Dictionary<int, CityRealAiNpcController>();
                NpcTypeCtrlDic.Add(npcCtrl.RoleId, ctrlDic);
            }

            if (ctrlDic.ContainsKey(npcCtrl.Uid))
            {
                Debug.LogErrorFormat(LogModule.CityAI, LogLevelType.Develop, "试图向 ContainerId = {0} 的房间或区域内添加一个 Npc UID = {1} 重复角色",  ContainerId, npcCtrl.Uid);
                return;
            }
            
            ctrlDic.Add(npcCtrl.Uid, npcCtrl);
        }

        /// <summary>
        /// 获取可以立即触发房间事件的NPC列表
        /// </summary>
        /// <param name="npcType"></param>
        /// <param name="eventTreeId"></param>
        /// <param name="roleType"></param>
        /// <param name="npcNum"></param>
        /// <param name="npcList"></param>
        /// <returns></returns>
        public virtual bool GetImmediatelyTriggerRoomEventNpcCtrlList(Vector3 linkNpcCfg, int eventTreeId, int needNpcCtrlNum, List<CityRealAiNpcController> npcList, List<List<CityRealAiNpcController>> allNpcList)
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var npcCtrl = subKeyValuePair.Value;
                    if (!CheckImmediatelyTriggerRoomEventNpcCtrlCondition(linkNpcCfg, eventTreeId, npcCtrl))
                    {
                        continue;
                    }

                    bool isContains = false;
                    for (int i = 0; i < allNpcList.Count; i++)
                    {
                        if (allNpcList[i].Contains(npcCtrl))
                        {
                            isContains = true;
                            break;
                        }
                    }

                    if (isContains)
                    {
                        continue;
                    }

                    npcList.Add(npcCtrl);
                    needNpcCtrlNum--;
                    if (needNpcCtrlNum <= 0)
                    {
                        return true;
                    }
                }

            }
            return false;
        }

        protected bool CheckImmediatelyTriggerRoomEventNpcCtrlCondition(Vector3 linkNpcCfg,  int eventTreeId, CityRealAiNpcController npcCtrl)
        {
            if ((int)linkNpcCfg.x == (int)CityRealGetNpcConditonType.RoleTag)
            {
                if ((int)linkNpcCfg.y != npcCtrl.RoleTag)
                {
                    return false;
                }
            }
            else if ((int)linkNpcCfg.x == (int)CityRealGetNpcConditonType.RoleType)
            {
                if ((int)linkNpcCfg.y != npcCtrl.RoleId)
                {
                    return false;
                }
            }
            
            var treeConfig = _cfgMgr.GetAiEventTreeConfig(eventTreeId);
            if (treeConfig.event_tree_id == _cfgMgr.EmptyEventTreeCfg.event_tree_id || treeConfig.event_array.Length <= 0)
            {
                return false;
            }
            
            if (!npcCtrl.IsAlive) // 当NPC处于隐藏状态时，如果要执行的事件树的第一个事件不是显示事件，则执行失败。
            {
                var eventCfg = _cfgMgr.GetAiEventConfig((int)treeConfig.event_array[0].x);

                if (eventCfg.event_type == (int)CityRealEventType.NormalEvent)
                {
                    return false;
                }

                if (eventCfg.parameter != CityRealAiConst.NpcActiveTag && eventCfg.parameter != CityRealAiConst.NpcInCityTag)
                {
                    return false;
                }
            }

            var treeConditionList = treeConfig.condition;
            if (treeConditionList != null && treeConditionList.Length > 0)
            {
                for (int i = 0; i < treeConditionList.Length; i++)
                {
                    var treeCondition = treeConditionList[i];
                    if ((int)treeCondition.x == (int)CityRealEventConditionType.CurrentEventTree)
                    {
                        if (npcCtrl.TreeConfig.event_tree_id != (int)treeCondition.y)
                        {
                            return false;
                        }
                    }
                    else
                    {
                        if (npcCtrl.TreeType == CityRealEventTreeType.SpecialEventTree)
                        {
                            return false;
                        }
                    }
                }
            }
            else
            {
                if (npcCtrl.TreeType == CityRealEventTreeType.SpecialEventTree)
                {
                    return false;
                }
            }

            return true;
        }

        public virtual bool CheckNeedAndRunNpc(CityRealAiNpcController npcCtrl)
        {
            return false;
        }

        public virtual CityRealAiNpcController RemoveNpcCtrl(int roleId, int uid)
        {
            if (!NpcTypeCtrlDic.TryGetValue(roleId, out var npcCtrlDic))
            {
#if DEVELOPMENT_BUILD || UNITY_EDITOR
                Debug.LogWarningFormat(LogModule.CityAI, LogLevelType.Develop, "试图在 ContainerId = {0} 的房间或区域内移除一个 Npc RoleType = {1} UID = {2} 不存在的角色", ContainerId, roleId, uid);
#endif
                return null;
            }
            if (!npcCtrlDic.TryGetValue(uid, out var npcCtrl))
            {            
#if DEVELOPMENT_BUILD || UNITY_EDITOR
                Debug.LogWarningFormat(LogModule.CityAI, LogLevelType.Develop, "试图在 ContainerId = {0} 的房间或区域内移除一个 Npc RoleType = {1} UID = {2} 不存在的角色", ContainerId, roleId, uid);
#endif
                return null;
            }
            npcCtrlDic.Remove(uid);
            return npcCtrl;
        }

        public CityRealAiGoodsController GetOrCreateGoodsCtrl(int goodsType)
        {
            if (!GoodsCtrlDic.TryGetValue(goodsType, out var goods))
            {
                goods = new CityRealAiGoodsController(ContainerId, this, goodsType);
                goods.UpdateContainer(this);
                GoodsCtrlDic.Add(goodsType, goods);
            }
            return goods;
        }

        public void RemoveGoodsCtrl(int goodsType)
        {
            if (GoodsCtrlDic.TryGetValue(goodsType, out var goodsCtrl))
            {
                goodsCtrl.Dispose();
                GoodsCtrlDic.Remove(goodsType);
            }
        }
        
        public virtual CityRealAiEventPointInfo GetEventPointInfo(int uid, int executeEventId, CityRealEventPointState state, string moveGoodsName)
        {
            bool isRoom = this is CityRealAiRoomManager;

            List<CityRealAiEventPointInfo> pointInfos = ListPool<CityRealAiEventPointInfo>.Get();

            CityRealAiEventPointInfo demandEventPoint = null;
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                // 检查房间事件点是否解锁
                if (isRoom)
                {
                    int buildingId = ContainerId;
                    if (keyValuePair.Value.UnlockBuildId > 0)
                    {
                        buildingId = keyValuePair.Value.UnlockBuildId;
                    }
                    if (keyValuePair.Value.UnlockLevel > 0)
                    {
                        int buildingLevel = CityRealAiCSharpCallLuaManager.GetBuildingLevel(buildingId);
                        if (buildingLevel < keyValuePair.Value.UnlockLevel)
                        {
                            continue;
                        }
                    }
                    if (keyValuePair.Value.FacilityId > 0)
                    {
                        int facilityLevel = CityRealAiCSharpCallLuaManager.GetFacilityLevel(buildingId, keyValuePair.Value.FacilityId);
                        if (facilityLevel <= 0)
                        {
                            continue;
                        }
                    }
                }

                if (!keyValuePair.Value.CheckExistMoveGoods(moveGoodsName, uid, executeEventId, state))
                {
                    continue;
                }
                
                var executeEventPoint = keyValuePair.Value.GetEventPoint(uid, executeEventId, state);
                if (executeEventPoint != null)
                {
                    var isDemand = keyValuePair.Value.CheckEventDemand(executeEventPoint.EventConfig.demand);
                    if (isDemand)
                    {
                        ListPool<CityRealAiEventPointInfo>.Release(pointInfos);
                        return executeEventPoint;
                    }
                    
                    pointInfos.Add(executeEventPoint);
                }
            }

            if (pointInfos.Count > 0)
            {
                demandEventPoint = pointInfos[UnityEngine.Random.Range(0, pointInfos.Count)];
            }
            ListPool<CityRealAiEventPointInfo>.Release(pointInfos);

            return demandEventPoint;
        }

        public virtual CityRealAiEventPointInfo GetEventPointInfo(int uid, int executeEventId, CityRealEventPointState state)
        {
            bool isRoom = this is CityRealAiRoomManager;

            List<CityRealAiEventPointInfo> pointInfos = ListPool<CityRealAiEventPointInfo>.Get();

            CityRealAiEventPointInfo demandEventPoint = null;
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                // 检查房间事件点是否解锁
                if (isRoom)
                {
                    int buildingId = ContainerId;
                    if (keyValuePair.Value.UnlockBuildId > 0)
                    {
                        buildingId = keyValuePair.Value.UnlockBuildId;
                    }
                    if (keyValuePair.Value.UnlockLevel > 0)
                    {
                        int buildingLevel = CityRealAiCSharpCallLuaManager.GetBuildingLevel(buildingId);
                        if (buildingLevel < keyValuePair.Value.UnlockLevel)
                        {
                            continue;
                        }
                    }
                    if (keyValuePair.Value.FacilityId > 0)
                    {
                        int facilityLevel = CityRealAiCSharpCallLuaManager.GetFacilityLevel(buildingId, keyValuePair.Value.FacilityId);
                        if (facilityLevel <= 0)
                        {
                            continue;
                        }
                    }
                }
                
                var executeEventPoint = keyValuePair.Value.GetEventPoint(uid, executeEventId, state);
                if (executeEventPoint != null)
                {
                    var isDemand = keyValuePair.Value.CheckEventDemand(executeEventPoint.EventConfig.demand);
                    if (isDemand)
                    {
                        ListPool<CityRealAiEventPointInfo>.Release(pointInfos);
                        return executeEventPoint;
                    }
                    
                    pointInfos.Add(executeEventPoint);
                }
            }

            if (pointInfos.Count > 0)
            {
                demandEventPoint = pointInfos[UnityEngine.Random.Range(0, pointInfos.Count)];
            }
            ListPool<CityRealAiEventPointInfo>.Release(pointInfos);

            return demandEventPoint;
        }

        public virtual CityRealAiEventPointInfo GetEventPointInfo(int uid, int executeEventId, CityRealEventPointState state1, CityRealEventPointState state2)
        {
            bool isRoom = this is CityRealAiRoomManager;
            
            List<CityRealAiEventPointInfo> pointInfos = ListPool<CityRealAiEventPointInfo>.Get();
            
            CityRealAiEventPointInfo demandEventPoint = null;
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                // 检查房间事件点是否解锁
                if (isRoom)
                {
                    int buildingId = ContainerId;
                    if (keyValuePair.Value.UnlockBuildId > 0)
                    {
                        buildingId = keyValuePair.Value.UnlockBuildId;
                    }
                    if (keyValuePair.Value.UnlockLevel > 0)
                    {
                        int buildingLevel = CityRealAiCSharpCallLuaManager.GetBuildingLevel(buildingId);
                        if (buildingLevel < keyValuePair.Value.UnlockLevel)
                        {
                            continue;
                        }
                    }
                    if (keyValuePair.Value.FacilityId > 0)
                    {
                        int facilityLevel = CityRealAiCSharpCallLuaManager.GetFacilityLevel(buildingId, keyValuePair.Value.FacilityId);
                        if (facilityLevel <= 0)
                        {
                            continue;
                        }
                    }
                }
                
                var executeEventPoint = keyValuePair.Value.GetEventPoint(uid, executeEventId, state1, state2);
                if (executeEventPoint != null)
                {
                    var isDemand = keyValuePair.Value.CheckEventDemand(executeEventPoint.EventConfig.demand);
                    if (isDemand)
                    {
                        ListPool<CityRealAiEventPointInfo>.Release(pointInfos);
                        return executeEventPoint;
                    }
                    
                    pointInfos.Add(executeEventPoint);
                }
            }
            
            if (pointInfos.Count > 0)
            {
                demandEventPoint = pointInfos[UnityEngine.Random.Range(0, pointInfos.Count)];
            }
            ListPool<CityRealAiEventPointInfo>.Release(pointInfos);

            return demandEventPoint;
        }


        public virtual CityRealAiEventPointInfo GetEventPointInfo(int uid, int executeEventId, params CityRealEventPointState[] stateList)
        {
            bool isRoom = this is CityRealAiRoomManager;
            
            List<CityRealAiEventPointInfo> pointInfos = ListPool<CityRealAiEventPointInfo>.Get();
            
            CityRealAiEventPointInfo demandEventPoint = null;
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                // 检查房间事件点是否解锁
                if (isRoom)
                {
                    int buildingId = ContainerId;
                    if (keyValuePair.Value.UnlockBuildId > 0)
                    {
                        buildingId = keyValuePair.Value.UnlockBuildId;
                    }
                    if (keyValuePair.Value.UnlockLevel > 0)
                    {
                        int buildingLevel = CityRealAiCSharpCallLuaManager.GetBuildingLevel(buildingId);
                        if (buildingLevel < keyValuePair.Value.UnlockLevel)
                        {
                            continue;
                        }
                    }
                    if (keyValuePair.Value.FacilityId > 0)
                    {
                        int facilityLevel = CityRealAiCSharpCallLuaManager.GetFacilityLevel(buildingId, keyValuePair.Value.FacilityId);
                        if (facilityLevel <= 0)
                        {
                            continue;
                        }
                    }
                }
                
                var executeEventPoint = keyValuePair.Value.GetEventPoint(uid, executeEventId, stateList);
                if (executeEventPoint != null)
                {
                    var isDemand = keyValuePair.Value.CheckEventDemand(executeEventPoint.EventConfig.demand);
                    if (isDemand)
                    {
                        ListPool<CityRealAiEventPointInfo>.Release(pointInfos);
                        return executeEventPoint;
                    }
                    
                    pointInfos.Add(executeEventPoint);
                }
            }
            
            if (pointInfos.Count > 0)
            {
                demandEventPoint = pointInfos[UnityEngine.Random.Range(0, pointInfos.Count)];
            }
            ListPool<CityRealAiEventPointInfo>.Release(pointInfos);

            return demandEventPoint;
        }
        
        public bool CheckExistMoveGoods(string moveGoodsName, int uid, int eventId, CityRealEventPointState state)
        {
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                var isExistMoveGoods = keyValuePair.Value.CheckExistMoveGoods(moveGoodsName, uid, eventId, state);
                if (isExistMoveGoods)
                {
                    return true;
                }
            }

            return false;
        }

        public CityRealAiEventPointInfo GetCommodityBubbleEventInfo(int bubbleType)
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    var bubbleEventInfo = subKeyValuePair.Value.CheckExistCommodityBubble(bubbleType);
                    if (bubbleEventInfo != null)
                    {
                        return bubbleEventInfo;
                    }
                }
            }

            return null;
        }

        public Vector3 GetWorldPos(Vector3 localPos)
        {
            if (RoomRootTran == null)
            {
                return localPos;
            }

            return RoomRootTran.TransformPoint(localPos);
        }

        public virtual void OnUpdate()
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    subKeyValuePair.Value.OnUpdate();
                }
            }
        }

        public virtual void OnPause(bool isPause)
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    subKeyValuePair.Value.OnPause(isPause);
                }
            }
        }

        public virtual void OnResetNpc()
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    subKeyValuePair.Value.Dispose();
                }
            }
            NpcTypeCtrlDic.Clear();
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                var goodsCtrl = keyValuePair.Value;
                goodsCtrl.OnResetEvent();
            }
        }

        public virtual void OnCloseBusiness()
        {
        }

        public virtual void Dispose()
        {
            foreach (var keyValuePair in NpcTypeCtrlDic)
            {
                foreach (var subKeyValuePair in keyValuePair.Value)
                {
                    subKeyValuePair.Value.Dispose();
                }
            }
            NpcTypeCtrlDic.Clear();
            foreach (var keyValuePair in GoodsCtrlDic)
            {
                var goodsCtrl = keyValuePair.Value;
                goodsCtrl.Dispose();
            }
        }
    }
}
